/*
 * @Author: chengsl
 * @Date: 2023-05-08 11:22:34
 * @LastEditors: chengsl
 * @LastEditTime: 2023-05-10 17:17:32
 * @Description: 微应用 入口文件
 */
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
import router from './router/routers'
import './router/index' // 路由
import { createRouter, createWebHistory } from 'vue-router'
import ElementPlus from 'element-plus'
import * as ElIconModules from '@element-plus/icons-vue'
import 'element-plus/theme-chalk/index.css'

import 'normalize.css/normalize.css'
import './assets/styles/index.scss'
import './assets/styles/element-variables.scss'

import './assets/icons' // icon
import '@/assets/iconfont/iconfont.css'

import { systemEnName } from './settings'

import './public-path'
import common from '@/utils/qiankun-common-vue3' // 导入封装 qiankun 主子应用通讯的方法
import { qiankunRoutes, asyncQiankunRouters } from '@/router/qiankun-router'

let qiankunRouter = null
let app = null

const activePath =
  process.env.NODE_ENV === 'development'
    ? `/${systemEnName}/`
    : `/udaam-ui/${systemEnName}/`

/* 创建 qiankun环境下的 router 实例   */
const createQinkunRouter = () =>
  createRouter({
    history: createWebHistory(
      window.__POWERED_BY_QIANKUN__ ? activePath : process.env.BASE_URL
    ),
    routes: qiankunRoutes,
    strict: false,
    scrollBehavior: () => ({ left: 0, top: 0 }),
  })

/**
 * @description: 渲染函数
 * @param {*} container
 */
function render({ container } = {}) {
  console.log(`现在进入子应用${systemEnName} render阶段逻辑`)
  // console.log('container:', container)
  try {
    qiankunRouter = createQinkunRouter()
    console.log('qiankunRouter---', qiankunRouter)
    /* 注册路由守卫 */
    asyncQiankunRouters(qiankunRouter)
    app = createApp(App)
    app
      .use(store)
      .use(window.__POWERED_BY_QIANKUN__ ? qiankunRouter : router)
      .use(ElementPlus)
      .use() // 注册权限指令
      .mount(
        container
          ? container.querySelector(`#${systemEnName}`)
          : `#${systemEnName}`
      )
    // common.getPermissionDirective(store, app)
    
      const checkPermission = (value) => {
        return common.getCheckPermission(store, value)
      }
      app.config.globalProperties.$checkPermission = checkPermission

    console.log('app----', app)
    /** *************** 引入 element-plus 的图标 *******************/
    Object.keys(ElIconModules).forEach(function (key) {
      app.component(ElIconModules[key].name, ElIconModules[key])
    })
    /** *************** 全局组件 *******************/ // 若要按需引入 请替换掉此处逻辑
    const components = require.context('@/components', true, /index\.vue$/)
    components.keys().forEach(componentPath => {
      const componentEntity = components(componentPath).default
      if (componentEntity.name) {
        app.component(componentEntity.name, componentEntity)
      }
    })
    if (process.env.NODE_ENV === 'development') {
      const appDiv = document.createElement('div')
      appDiv.__vue__ = app
      document.body.appendChild(appDiv)
    }
  } catch (error) {
    console.log(`🐞🐞🐞子应用${systemEnName}的render阶段逻辑执行出错:`, error)
  }
}

if (!window.__POWERED_BY_QIANKUN__) {
  render()
}

/**
 * bootstrap 只会在微应用初始化的时候调用一次，下次微应用重新进入时会直接调用 mount 钩子，不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化，比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap(props) {
  console.log(`现在进入子应用${systemEnName}的bootstraped阶段`)
  common.setCommonData(props)
}

/**
 * 应用每次进入都会调用 mount 方法，通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  try {
    console.log(`现在进入子应用${systemEnName}的mount周期`)
    console.log(`主应用下发给子应用${systemEnName}的props`, props)
    console.log('common:', common)
    /** 将父应用下发的数据存储到子应用中，命名空间固定为 global */
    common.initGlobalState(store, props)
    console.log('子应用mount - store', store)
    // 主应用手动点击资源发现按钮，加载子应用资源
    if (props.collectSource) {
      // 获取主应用下发的资源去重方法
      const distinctSource = props.distinctSource
      // 收集子应用暴露的资源
      const resourceList = await saveAutoDiscovery()
      // 资源去重后暴露出来的资源
      console.log(store.state.global, 'store.state.global')
      const sources = distinctSource(store.state.global.sources, resourceList)
      // 子应用改变 state 并通知父应用
      store.dispatch('global/setGlobalState', { sources })
      console.log(`子应用${systemEnName} mount阶段逻辑结束`)
      return
    }
    render(props)
  } catch (error) {
    console.log(`🐞🐞🐞子应用${systemEnName}的mount阶段逻辑执行出错：`, error)
  }
}

/**
 * 应用每次 切出/卸载 会调用的方法，通常在这里我们会卸载微应用的应用实例
 */
export async function unmount() {
  try {
    console.log(`现在进入子应用${systemEnName}的unmount阶段`)
    console.log('app:', app)
    app.unmount()
    app._container.innerHTML = ''
    app = null
    qiankunRouter = null
  } catch (error) {
    console.log(`🐞🐞🐞子应用${systemEnName}的 unmount 阶段逻辑执行出错：`, error)
  }
}

/**
 * 可选生命周期钩子，仅使用 loadMicroApp 方式加载微应用时生效
 */
export async function update(props) {
  console.log(
    `现在进入子应用${systemEnName}的update阶段,仅使用 loadMicroApp 方式加载微应用时生效`
  )
  console.log('update props', props)
  // 主应用手动点击资源发现按钮，加载子应用资源
  if (props.collectSource) {
    // 获取主应用下发的资源去重方法
    const distinctSource = props.distinctSource
    // 收集子应用暴露的资源
    const resourceList = await saveAutoDiscovery()
    // 资源去重后暴露出来的资源
    const sources = distinctSource(store.state.global.sources, resourceList)
    // 子应用改变 state 并通知父应用
    store.dispatch('global/setGlobalState', { sources })
  }
}

/**
 * @description: 子应用收集所有的页面资源，并将资源暴露
 */
export async function saveAutoDiscovery() {
  try {
    console.log(`子应用${systemEnName}开始收集资源`)
    const resourceList = []
    const resources = await require.context('@/views/', true, /resource\.js$/)
    resources.keys().forEach(resourcePath => {
      const entity = resources(resourcePath)
      // noCollect为 true则资源不暴露，如 home 页面则不暴露
      if (entity.resource && !entity.noCollect) {
        resourceList.push({
          ...entity.resource,
          component: 'Layout',
        })
      }
    })
    console.log(`收集子应用${systemEnName}资源结束`, resourceList)
    return resourceList
  } catch (error) {
    console.error(error)
  }
}
